package com.vincent.common;

import com.vincent.acceptor.Acceptor;
import com.vincent.leader.Leader;
import com.vincent.message.RequestMessage;
import com.vincent.replica.Replica;
import com.vincent.utils.Config;
import com.vincent.utils.RequestCommand;
import com.vincent.utils.SimpleOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Created by wensen on 2016/12/7.
 * 环境信息
 */
public class Environment {

    private static Logger LOGGER = LoggerFactory.getLogger(Environment.class);

    public static final int NACCEPTORS = 3;
    public static final int NREPLICAS = 2;
    public static final int NLEADERS = 2;
    public static final int NREQUESTS = 40;
    public static final int NCONFIGS = 3;

    private Map<Integer, Process> procs;

    public Environment() {

        procs = new HashMap<Integer, Process>();
    }

    //发送消息
    public void sendMessage(int dst, Message msg){

        if (procs.containsKey(dst)) {
            this.procs.get(dst).deliver(msg);
//            LOGGER.debug("Env found dst");
        }
//        LOGGER.debug("Env not found dst {}", dst);
    }

    public void addProc(Process prc) {
        this.procs.put(prc.id(), prc);
    }

    public void removeProc(int pid) {
        if (this.procs.containsKey(pid)) {
            this.procs.remove(pid);
        }
    }

    public void run() {

        ExecutorService exec = Executors.newFixedThreadPool(100);

        Config initialConfig = new Config();

        int c = 0;

        //创建replica
        for (int i = 0; i< NREPLICAS; i++) {
            int pid = i;
            exec.submit(new Replica(this, pid, initialConfig));
//            new Replica(this, pid, initialConfig);
            initialConfig.replicas().add(pid);
        }
        //创建acceptor
        for (int i = 2; i < NACCEPTORS + 2; i++) {
            int pid = i;
            exec.submit(new Acceptor(this, pid));
            initialConfig.acceptors().add(pid);
        }

        for (int i = 5; i < NLEADERS + 5; i++) {
            int pid = i;
            exec.submit(new Leader(this, pid, initialConfig));
            initialConfig.leaders().add(pid);
        }

        for (int i = 7; i < NREPLICAS + 7; i++) {
            int pid = i;
            for (Integer r : initialConfig.replicas()) {
                LOGGER.debug("Env initialConfig: r-{}", r);
                Command cmd = new RequestCommand(pid, 0, new SimpleOperation());
                this.sendMessage(r, new RequestMessage(pid, cmd));
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    public static void main(String[] args) {
        Environment env = new Environment();
        env.run();
    }

}
